using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class sCameras : MonoBehaviour
{
	private static sCameras instance = null;

	private sCameras () {}

	public static sCameras Instance
	{
		get
		{
			return instance;
		}
	}
	
	void Awake()
	{
		instance = GetComponent<sCameras>();
		m_tCamera = GetComponent<Transform>();
		m_oCamera = GetComponent<Camera>();
	}
	
	Transform m_tCamera;
	Camera m_oCamera;
	CameraState m_oState;
	Dictionary<string, string> m_aoStateCameras;
	Dictionary<string, CameraState> m_aoCameras;
	
	// common stuff for cameras
	GameObject m_oOrbit;
	Transform m_tOrbit;
	public Transform m_tTarget;
	
	public Transform getOrbitTransform() { return m_tOrbit; }
	public Transform getCameraTransform() { return m_tCamera; }
	public Camera getCamera() { return m_oCamera; }
	
	void addCamera<charState>(string sCamera)
	{
		string state = typeof(charState).ToString();
		m_aoStateCameras.Add(state, sCamera);
	}
	
	void Start ()
	{
		m_oState = GetComponent<CameraThirdPerson>();
		
		// init the orbit object and transform
		m_oOrbit = new GameObject("orbitCameraHelper");
		m_tOrbit = m_oOrbit.transform;
		m_tOrbit.position = m_tTarget.position + Vector3.forward;
		m_tOrbit.setForward(m_tTarget.forward, Vector3.up);
		
		m_aoStateCameras = new Dictionary<string, string>();
		
		// bind cameras to each character state
		addCamera< CharacterStateStanding>					("CameraThirdPerson");
		addCamera< CharacterStateCoveringHigh>				("CameraThirdPerson");
		addCamera< CharacterStateCoveringLow>				("CameraThirdPerson");
		addCamera< CharacterStateStandingShot>				("CameraShootingRight");
		addCamera< CharacterStateToCover>					("CameraThirdPerson");
		addCamera< CharacterStateUncovering>				("CameraThirdPerson");
		addCamera< CharacterStateCoveringLowShotLeft>		("CameraShootingLeft");
		addCamera< CharacterStateCoveringLowShotRight>		("CameraShootingRight");
		addCamera< CharacterStateCoveringLowShotUp>			("CameraShooting");
	}
	
	public void changeState(string _sCharacterState)
	{
		m_oState.exit();
		m_oState = (CameraState)GetComponent(m_aoStateCameras[_sCharacterState]);
		m_oState.enter();
	}
	
	void Update()
	{
		m_oState.update();
		
		Vector3 vNewPosition = m_oState.getRealPosition();
		m_tCamera.position = MathHelper.blendPositions( m_tCamera.position, vNewPosition, Time.deltaTime * m_oState.fSmooth);
		Vector3 vNewForward = m_oState.getRealTargetPosition() - vNewPosition;
		vNewForward = MathHelper.blendDirections( m_tCamera.forward, vNewForward, Time.deltaTime * m_oState.fSmooth);
		vNewForward.Normalize();
		m_tCamera.setForward(vNewForward, m_tTarget.up);
		
		m_oCamera.fov = MathHelper.blend(m_oCamera.fov, m_oState.FOV, Time.deltaTime * m_oState.fSmooth);
		
		updateCollisions();
		
		Vector3 p1 = m_tTarget.position;
		Vector3 p2 = p1 + m_tOrbit.forward * 3.0f;
		Debug.DrawLine(p1, p2);
	}
	
	void updateCollisions()
	{
		RaycastHit hitInfo;
		int iLayer = 1 << 8 | 1 << 9;
		if (Physics.Linecast(m_oState.getRealTargetPosition() + new Vector3(0.0f, 0.75f, 0.0f), m_tCamera.position, out hitInfo, iLayer))
		{
			m_tCamera.position = hitInfo.point;
		}
	}
}
